package com.nulldev.util.gui.themeAPI;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.RenderingHints;
import java.awt.SystemColor;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JMenu;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JToggleButton;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.tree.DefaultTreeCellRenderer;

import com.nulldev.util.JVM.JVM;
import com.nulldev.util.VariableAPI.ArrayUtils;
import com.nulldev.util.data.Variables;
import com.nulldev.util.data.Images.ColorUtil;
import com.nulldev.util.gui.customSwing.legacyBorders.RoundedBorder;
import com.nulldev.util.gui.fontAPI.FontManager;
import com.nulldev.util.gui.swingAPI.Swing;
import com.nulldev.util.gui.swingAPI.Swing.ScrollDirection;
import com.nulldev.util.gui.themeAPI.ThemeAPI.ThemingOptions;

import sun.swing.SwingUtilities2;

class SwingThemeAPI {

	private static final Object AA_TEXT_PROPERTY_KEY = new StringBuffer("AATextInfoPropertyKey");

	public static void applySwingTheme(final Theme theme, final Container c, final ThemingOptions... options) {
		Variables.requireNonNull(theme, "theme");
		Variables.requireNonNull(c, "c");
		final boolean useSystemLF = ArrayUtils.contains(options, ThemingOptions.APPLY_SYSTEM_LOOK_AND_FEEL);
		if (useSystemLF) {
			try {
				UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
			} catch (Exception ex) {
				JVM.errorln(ex);
			}
		}
		final boolean applySystemFont = ArrayUtils.contains(options, ThemingOptions.APPLY_SYSTEM_FONT);
		final boolean skipTransparent = ArrayUtils.contains(options, ThemingOptions.SKIP_TRANSPARENT_ELEMENTS);
		final boolean noAAWorkaround = ArrayUtils.contains(options, ThemingOptions.DISABLE_AA_TEXT_INFO_WORKAROUND);
		final boolean enableJEditorPane = ArrayUtils.contains(options, ThemingOptions.APPLY_TO_JEDITOR_PANE);
		final List<Component> items = Swing.getAllComponents(c);
		if (applySystemFont)
			c.setFont(FontManager.getFontSetAsAWT());
		c.setForeground(theme.foregroundColor());
		if (c.getBackground() != ColorUtil.TRANSPARENT && !skipTransparent)
			c.setBackground(theme.backgroundColor());
		while (!items.isEmpty()) {
			for (final Component cmp : items) { // FIXME: Should we clone here just like in 2.x?
				if (cmp instanceof JComponent && !noAAWorkaround && JVM.version() <= 11f) {
					try {
						((JComponent) cmp).putClientProperty(AA_TEXT_PROPERTY_KEY,
								new SwingUtilities2.AATextInfo(RenderingHints.VALUE_TEXT_ANTIALIAS_ON, null));
					} catch (Exception e) {
						JVM.errorln(e);
					}
				}
				if (cmp instanceof JMenu) {
					try {
						items.addAll(ArrayUtils.toArrayList(((JMenu) cmp).getMenuComponents()));
						if (cmp.getBackground() != ColorUtil.TRANSPARENT && !skipTransparent) {
							cmp.setBackground(theme.backgroundColor());
						} else if (cmp.getBackground() == SystemColor.windowBorder) {
							cmp.setForeground(theme.foregroundColor());
						}
						((JMenu) cmp).setOpaque(true);

					} catch (Exception e) {
						JVM.errorln(e);
					}
				}
				if (cmp instanceof JToggleButton) {
					final JToggleButton jtgb = (JToggleButton) cmp;
					jtgb.setFocusable(false);
					jtgb.putClientProperty(AA_TEXT_PROPERTY_KEY, new SwingUtilities2.AATextInfo(RenderingHints.VALUE_TEXT_ANTIALIAS_ON, null));
					items.addAll(ArrayUtils.toArrayList(jtgb.getComponents()));
				}
				if (cmp instanceof JEditorPane) {
					final JEditorPane ed = (JEditorPane) cmp;
					if (enableJEditorPane) {
						ed.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
					}
				}
				if (cmp instanceof JButton && !(cmp instanceof JToggleButton)) {
					final JButton btn = (JButton) cmp;
					btn.setBorder(new RoundedBorder(5));
					btn.setFocusable(false);
				}
				if (cmp instanceof JCheckBox) {
					cmp.setFocusable(false);
				}
				if (cmp instanceof JComboBox) {
					cmp.setFocusable(false);
					items.addAll(ArrayUtils.toArrayList(((JComboBox<?>) cmp).getComponents()));
				}
				if (cmp instanceof JTabbedPane) {
					cmp.setFocusable(false);
				}
				if (cmp instanceof JTable) {
					final JTable jt = (JTable) cmp;
					items.addAll(ArrayUtils.toArrayList(jt.getComponents()));
					jt.putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY, new SwingUtilities2.AATextInfo(RenderingHints.VALUE_TEXT_ANTIALIAS_ON, null));
					if (jt.getTableHeader() != null) {
						jt.getTableHeader().setDefaultRenderer(new DefaultTableCellRenderer() {
							private static final long serialVersionUID = 5562533728256582276L;

							@Override
							public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row,
									int column) {
								final Component out = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
								if (out instanceof JComponent) {
									((JComponent) out).putClientProperty(SwingUtilities2.AA_TEXT_PROPERTY_KEY,
											new SwingUtilities2.AATextInfo(RenderingHints.VALUE_TEXT_ANTIALIAS_ON, null));
								}
								return out;
							}
						});
						if (applySystemFont)
							jt.getTableHeader().setFont(FontManager.getFontSetAsAWT(jt.getTableHeader().getFont().getSize()));
						jt.getTableHeader().setForeground(theme.foregroundColor());
						jt.getTableHeader().setBackground(theme.backgroundColor());
						jt.getTableHeader().putClientProperty(AA_TEXT_PROPERTY_KEY,
								new SwingUtilities2.AATextInfo(RenderingHints.VALUE_TEXT_ANTIALIAS_ON, null));
					}
				}
				if (cmp instanceof JTree) {
					final JTree tree = (JTree) cmp;
					tree.setCellRenderer(new DefaultTreeCellRenderer() {
						private static final long serialVersionUID = 1L;

						@Override
						public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean exp, boolean leaf, int row,
								boolean hasFocus) {
							super.getTreeCellRendererComponent(tree, value, sel, exp, leaf, row, hasFocus);

							setForeground(theme.foregroundColor());
							setBackground(theme.backgroundColor());
							setBackgroundNonSelectionColor(theme.backgroundColor());
							setBackgroundSelectionColor(theme.backgroundColor());

							return this;
						}
					});
				}
				if (cmp instanceof JScrollPane) {
					Swing.scroll((JScrollPane) cmp, ScrollDirection.UP);
				}
				if (applySystemFont)
					cmp.setFont(FontManager.getFontSetAsAWT(cmp.getFont().getSize()));
				if (cmp instanceof JSeparator) {
					cmp.setForeground(ColorUtil.TRANSPARENT);
					cmp.setBackground(ColorUtil.TRANSPARENT);
				} else {
					if (!(cmp instanceof JTabbedPane)) {
						cmp.setForeground(theme.foregroundColor());
					} else {
						if (cmp instanceof JProgressBar) {
							cmp.setForeground(Color.yellow);
						} else {
							if ((cmp instanceof JTabbedPane) && theme.isDarkTheme()) {
								// NOP
							} else {
								cmp.setForeground(theme.foregroundColor());
							}
						}
					}
					if (cmp.getBackground() != ColorUtil.TRANSPARENT && !skipTransparent) {
						cmp.setBackground(theme.backgroundColor());
					}
				}
				// TODO: Add back the PolySwing API.
				items.remove(0);
			}
		}
	}
}
